using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

using TTDotNet.Engine.ThreeDEngine;

namespace TTDotNet.Engine.GUI
{
    public class ListBox : Control
    {
        protected bool _newData;
        protected int _topItem;
        protected int _numDisplayed;
        private int alwaysDraw;
        private int selectedItem;
        protected float _itemHeight;
        private List<ListableItem> items;
        private ListBoxSlider vert;

        public event ListBoxDelegate OnSelectionChanged;
        public delegate void ListBoxDelegate();


        public ListBox(RectangleF screenRect, float slideWidth, string text, float fontSize, Color textColor, string fontName, float itemHeight, GameTexture bgUp)
        {
            _topItem = 0;
            _itemHeight = itemHeight;
            _fontSize = fontSize;
            _text = text;
            _fontSize = fontSize;
            _fontColor = textColor;
            textureUp = bgUp;
            _position = new PointF(screenRect.X, screenRect.Y);

            selectedItem = 0;

            _textRect = screenRect;

            items = new List<ListableItem>();

            System.Drawing.Font systemFont = new System.Drawing.Font(fontName, fontSize);
            _font = new Microsoft.DirectX.Direct3D.Font(Game.device, systemFont);

            SetSize(screenRect.Width, screenRect.Height);

            float slideLeft = _position.X + _size.Width - slideWidth;
            float slideTop = _position.Y;

            RectangleF slideBar = new RectangleF(new PointF(slideLeft, slideTop), new SizeF(slideWidth, _size.Height));

            vert = new ListBoxSlider(slideBar, true,
                                        Game.textureCacher.LoadTexture("artwork/colours/black.jpg"), Game.textureCacher.LoadTexture("artwork/colours/ttdOrange.jpg"));

            vert.ItemsShown = (int)(screenRect.Height / itemHeight);
        }

        public virtual ListableItem AddItem()
        {
            ListableItem item = new ListableItem();
            items.Add(item);
            item.SetSize(ItemWidth, ItemHeight);

            vert.NumberOfItems++;

            return item;
        }

        public virtual ListableItem AddItemAt(int num)
        {
            ListableItem item = new ListableItem();
            items.Insert(num, item);
            item.SetSize(ItemWidth, ItemHeight);

            vert.NumberOfItems = vert.NumberOfItems + 1;
            //vert.ItemsShown = 5;

            return item;
        }

        public ListableItem GetItem(int num) 
        {
            return items[num];
        }

        public void Add(ListableItem item)
        {
            items.Add(item);
        }

        public void Remove(ListableItem item)
        {
            items.Remove(item);
        }

        public void RemoveFromOnwards(int num)
        {
            items.RemoveRange(num, items.Count - num);
        }

        public override void ResizeBy(float widthFactor, float heightFactor)
        {
            base.ResizeBy(widthFactor, heightFactor);
            vert.ResizeBy(widthFactor, heightFactor);
        }

        protected virtual void ScrollDown()
        {
            if (_topItem + _numDisplayed < items.Count)
            {
                _topItem++;
            }
        }

        protected virtual void ScrollUp()
        {

        }

        protected override void OnMouseDown(Point cursor, bool[] buttons)
        {
            vert.MouseHandler(cursor, buttons, 0);

            for (int x = vert.TopItem; x < vert.TopItem + vert.NumberOfItems; x++)
            {
                if (x > items.Count - 1) break;

                Point myP = Point.Subtract(cursor, new Size((int)_size.X, (int)_size.Y));

                bool selected = items[x].MouseHandler(myP, buttons, 0);
            }
        }

        protected override void OnMouseRelease(Point cursor)
        {
            vert.MouseHandler(cursor, new bool[3], 0);

            for (int x = vert.TopItem; x < vert.TopItem + vert.NumberOfItems; x++)
            {
                if (x > items.Count - 1) break;

                Point myP = Point.Subtract(cursor, new Size((int)_size.X, (int)_size.Y));

                bool selected = items[x].MouseHandler(myP, new bool[3], 0);

                if (selected)
                {
                    if (x != selectedItem)
                    {
                        selectedItem = x;
                        if(OnSelectionChanged != null)
                        OnSelectionChanged();
                    }
                }
            }
        }

        protected override void OnZDelta(float zDelta)
        {
            vert.ScrollOnMouseWheel(zDelta);
        }

        public override void Render(PointF location)
        {
            Game.guiSprite.Transform = spriteTransform;
            Game.guiSprite.Draw(textureUp.Texture, Rectangle.Empty, Vector3.Empty, Vector3.Add(_renderPosition, new Vector3(location.X / WidthScale, location.Y / HeightScale, 0)), Color.White);

            vert.Render(location);

            vert.NumberOfItems = items.Count;
            location = PointF.Add(location, new Size((int)Position.X, (int)Position.Y));

            
            int itemNum = 0;

            for (int i = 0; i < alwaysDraw; i++)
            {
                if (i < items.Count)
                {
                    items[i].Position = new PointF(0, _itemHeight * itemNum++);
                    items[i].Render(location);
                }
            }

            int topItem = vert.TopItem;

            for (int i = topItem + alwaysDraw; i < topItem + vert.ItemsShown; i++)
            {
                if (i < items.Count)
                {
                    items[i].Position = new PointF(0, _itemHeight * itemNum++);
                    items[i].Render(location);
                }
            }

            

            
        }

        public int AlwaysDraw
        {
            get { return alwaysDraw; }
            set { alwaysDraw = value; }
        }

        public bool HasNewData
        {
            get { return _newData; }
        }

        public int ItemsVisible
        {
            get { return vert.ItemsShown; }
        }

        public float ItemWidth
        {
            get { return _size.Width - vert.Area.Width; }
        }

        public float ItemHeight
        {
            get { return _itemHeight; }
        }

        public int SelectedItem
        {
            get { return selectedItem; }
        }

    }

    public class ListBoxSlider : Control
    {
        private GameButton negative;
        private GameButton positive;
        private Label slider;
        private Label slideChannel;
        //private bool isVerticalSlider;
        
        private int numItems;
        private int itemsShown;

        public ListBoxSlider(RectangleF slideBar, bool vertical, GameTexture slideTex, GameTexture channelTex)
        {
            //_sprite = new Sprite(Game.device);

            slider = new Label(new RectangleF(slideBar.X + 2, slideBar.Y + slideBar.Width, slideBar.Width - 4, slideBar.Height - (2 * slideBar.Width))
                                , "", 10, Color.Yellow, "Arial", slideTex, DrawTextFormat.None);

            slideChannel = new Label(new RectangleF(slideBar.X, slideBar.Y + slideBar.Width, slideBar.Width, slideBar.Height - (2 * slideBar.Width)),
                                        "", 10, Color.White, "Arial", channelTex, DrawTextFormat.None);

            _position = slideBar.Location;

            itemsShown = 0;
            numItems = 0;

            _text = "Listboxslider!";

            SetSize(slideBar.Width, slideBar.Height);

            SetupButtons(slideBar);
        }

        public int NumberOfItems {
            get { return numItems; }
            set {
                if (value != numItems)
                {
                    numItems = value;
                    UpdateSliderSize();
                }
            }
        }

        private void SetupButtons(RectangleF slideBar)
        {
            negative = new GameButton(new RectangleF(slideBar.X, slideBar.Y, slideBar.Width, slideBar.Width), "", 10, Color.Black, "Arial",
                                        new GameTexture("artwork/64/list_slider_up_up.png"), new GameTexture("artwork/64/list_slider_up_down.png"));

            positive = new GameButton(new RectangleF(slideBar.X, slideBar.Y + slideChannel.Size.Height + slideBar.Width, slideBar.Width, slideBar.Width),
                                            "", 10, Color.Black, "Arial", new GameTexture("artwork/64/list_slider_down_up.png"), new GameTexture("artwork/64/list_slider_down_down.png"));

            negative.OnControl += new ControlDelegate(ScrollButton);
            negative.Tag = -1;
            positive.OnControl += new ControlDelegate(ScrollButton);
            positive.Tag = 1;
        }

        public Rectangle SlideChannelSize
        {
            set { 
                _size = value;
                UpdateSliderSize();
            }
        }

        

        public int TopItem
        {
            get
            {
                if (itemsShown == 0 || itemsShown >= numItems) return 0;

                float divisionHeight = (slideChannel.Size.Height - slider.Size.Height) / (numItems - itemsShown);
                float movedDown = (slider.Position.Y - slideChannel.Position.Y);

                float num = movedDown / divisionHeight;


                return (int)Math.Round(num);
            }
        }

        public int ItemsShown
        {
            get { return itemsShown; }
            set { itemsShown = value; UpdateSliderSize(); }
        }

        private void UpdateSliderSize()
        {
            float width = _size.Width - 4;

            float height = slideChannel.Size.Height / ((float)numItems / (float)itemsShown);
            
            if (itemsShown > numItems)
            {
                height = slideChannel.Size.Height;
            }
            
            slider.SetSize(width, height);
        }

        protected override void OnMouseDown(Point cursor, bool[] buttons)
        {
            //int _xOffset;
            //int _yOffset;

            ////Console.WriteLine("Down");

            if (negative.Contains(cursor))
            {
                negative.MouseHandler(cursor, buttons, 0);
            }
            else if (positive.Contains(cursor))
            {
                positive.MouseHandler(cursor, buttons, 0);
            }
            //else if (slider.Contains(cursor))
            //{
            //    _xOffset = 0;
            //    _yOffset = cursor.Y - _touchDownPoint.Y;

            //    float newX = slider.Position.X;
            //    float newY = slider.Position.Y + _yOffset;

            //    if (newY < _size.Top) { newY = _size.Top; }
            //    if (newY + slider.Size.Height > _size.Bottom) { newY = _size.Bottom - slider.Size.Height; }

            //    slider.Position = new PointF(newX, newY);

            //    _touchDownPoint.X += _xOffset;
            //    _touchDownPoint.Y += _yOffset;

            //    Console.WriteLine("= " + TopItem);
            //}
        }

        protected override void OnMouseRelease(Point cursor)
        {
            if (slideChannel.Contains(cursor))
            {
                float divisionHeight = slideChannel.Size.Height;

                if (numItems > itemsShown)
                {
                    divisionHeight = (slideChannel.Size.Height - slider.Size.Height) / (numItems - itemsShown);
                }

                if (cursor.Y > slider.Area.Bottom)
                {
                    slider.Position = new PointF(slider.Position.X, slider.Position.Y + divisionHeight);
                }
                else if (cursor.Y < slider.Area.Top)
                {
                    slider.Position = new PointF(slider.Position.X, slider.Position.Y - divisionHeight);
                }                

                //float newY = (slider.Position.Y + ((itemsShown * divisionHeight) * Math.Sign(cursor.Y - slider.Position.Y)));

                //if (newY < _size.Top) { newY = _size.Top; }
                //if (newY + slider.Size.Height > _size.Bottom) { newY = _size.Bottom - slider.Size.Height; }

                //slider.Position = new PointF(Position.X + 1, newY);
            }

            negative.MouseHandler(cursor, new bool[3], 0);
            positive.MouseHandler(cursor, new bool[3], 0);
        }

        public void ScrollOnMouseWheel(float zDelta)
        {
            ScrollButton(null, -Math.Sign(zDelta));
        }

        private void ScrollButton(object sender, object tag)
        {
            float divisionHeight = slideChannel.Size.Height;

            if (numItems > itemsShown)
            {
                divisionHeight = (slideChannel.Size.Height - slider.Size.Height) / (numItems - itemsShown);
            }

            PointF newPosition = new PointF(slider.Position.X, slider.Position.Y + (divisionHeight * (int)tag));

            if(newPosition.Y < slideChannel.Position.Y) newPosition.Y = slideChannel.Position.Y;
            if(newPosition.Y > (slideChannel.Area.Bottom - slider.Size.Height)) newPosition.Y = slideChannel.Area.Bottom - slider.Size.Height;

            slider.Position = newPosition;
        }   

        public override void Render(PointF location)
        {
            slideChannel.Render(location);
            slider.Render(location);

            negative.Render(location);
            positive.Render(location);
        }

    }
}
